package com.coupon.admin.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.coupon.admin.dto.AIRecommendationDTO;
import com.coupon.admin.dto.UserProfileDTO;
import com.coupon.admin.entity.Coupon;
import com.coupon.admin.entity.User;
import com.coupon.admin.entity.UserCoupon;
import com.coupon.admin.mapper.CouponMapper;
import com.coupon.admin.mapper.UserMapper;
import com.coupon.admin.mapper.UserCouponMapper;
import com.coupon.admin.service.AIPersonalizationService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * AI个性化策略服务实现类
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class AIPersonalizationServiceImpl implements AIPersonalizationService {
    
    private final UserMapper userMapper;
    private final CouponMapper couponMapper;
    private final UserCouponMapper userCouponMapper;
    private final ObjectMapper objectMapper;
    private final RedisTemplate<String, Object> redisTemplate;
    
    private static final String USER_PROFILE_KEY = "user:profile:";
    private static final String RECOMMENDATION_CACHE_KEY = "recommendation:";
    
    @Override
    public List<Long> generatePersonalizedCoupons(Long userId, Integer limit) {
        // 检查缓存
        String cacheKey = RECOMMENDATION_CACHE_KEY + userId + ":" + limit;
        Object cached = redisTemplate.opsForValue().get(cacheKey);
        if (cached != null) {
            return (List<Long>) cached;
        }
        
        // 获取用户画像
        UserProfileDTO userProfile = getUserProfile(userId);
        
        // 使用混合推荐算法
        List<Long> recommendations = hybridRecommend(userId, limit);
        
        // 缓存结果
        redisTemplate.opsForValue().set(cacheKey, recommendations, 30, TimeUnit.MINUTES);
        
        log.info("为用户{}生成个性化券推荐，数量：{}", userId, recommendations.size());
        return recommendations;
    }
    
    @Override
    public Coupon generateDynamicCoupon(Long userId, String baseCouponId) {
        // 获取用户画像
        UserProfileDTO userProfile = getUserProfile(userId);
        
        // 获取基础券模板
        Coupon baseCoupon = couponMapper.selectById(Long.valueOf(baseCouponId));
        if (baseCoupon == null) {
            throw new RuntimeException("基础券模板不存在");
        }
        
        // 创建动态券
        Coupon dynamicCoupon = new Coupon();
        dynamicCoupon.setName(baseCoupon.getName() + "（个性化）");
        dynamicCoupon.setType(baseCoupon.getType());
        dynamicCoupon.setDescription("基于您的消费习惯个性化定制");
        
        // 根据用户画像调整券面值
        adjustCouponValueByProfile(dynamicCoupon, userProfile, baseCoupon);
        
        // 设置个性化有效期
        adjustCouponValidityByProfile(dynamicCoupon, userProfile);
        
        // 设置个性化使用门槛
        adjustCouponThresholdByProfile(dynamicCoupon, userProfile);
        
        dynamicCoupon.setStatus("DRAFT");
        dynamicCoupon.setMerchantId(baseCoupon.getMerchantId());
        dynamicCoupon.setCreatorId(baseCoupon.getCreatorId());
        dynamicCoupon.setAiWeight(BigDecimal.valueOf(1.5)); // 提高AI权重
        
        couponMapper.insert(dynamicCoupon);
        
        log.info("为用户{}生成动态券，券ID：{}", userId, dynamicCoupon.getId());
        return dynamicCoupon;
    }
    
    @Override
    public boolean adjustCouponRules(Long couponId, Map<String, Object> adjustmentData) {
        Coupon coupon = couponMapper.selectById(couponId);
        if (coupon == null) {
            throw new RuntimeException("券不存在");
        }
        
        // 只有草稿状态的券才能调整
        if (!"DRAFT".equals(coupon.getStatus())) {
            throw new RuntimeException("只有草稿状态的券才能调整规则");
        }
        
        // 根据调整数据修改券规则
        if (adjustmentData.containsKey("threshold")) {
            coupon.setThreshold(new BigDecimal(adjustmentData.get("threshold").toString()));
        }
        
        if (adjustmentData.containsKey("value")) {
            coupon.setValue(new BigDecimal(adjustmentData.get("value").toString()));
        }
        
        if (adjustmentData.containsKey("validEndTime")) {
            coupon.setValidEndTime(LocalDateTime.parse(adjustmentData.get("validEndTime").toString()));
        }
        
        boolean result = couponMapper.updateById(coupon) > 0;
        
        if (result) {
            log.info("智能调整券{}规则成功", couponId);
        }
        
        return result;
    }
    
    @Override
    public boolean updateUserProfile(Long userId, UserProfileDTO profileDTO) {
        User user = userMapper.selectById(userId);
        if (user == null) {
            throw new RuntimeException("用户不存在");
        }
        
        try {
            // 更新用户画像数据
            if (profileDTO.getConsumeFrequency() != null) {
                user.setConsumeFrequency(profileDTO.getConsumeFrequency());
            }
            
            if (profileDTO.getAvgOrderValue() != null) {
                user.setAvgOrderValue(profileDTO.getAvgOrderValue().doubleValue());
            }
            
            if (profileDTO.getPreferredCategories() != null) {
                user.setPreferredCategories(objectMapper.writeValueAsString(profileDTO.getPreferredCategories()));
            }
            
            if (profileDTO.getPriceSensitivity() != null) {
                user.setPriceSensitivity(profileDTO.getPriceSensitivity());
            }
            
            if (profileDTO.getUserTags() != null) {
                user.setTags(objectMapper.writeValueAsString(profileDTO.getUserTags()));
            }
            
            if (profileDTO.getConsumptionHabits() != null) {
                user.setProfile(objectMapper.writeValueAsString(profileDTO.getConsumptionHabits()));
            }
            
            boolean result = userMapper.updateById(user) > 0;
            
            if (result) {
                // 清除缓存
                String cacheKey = USER_PROFILE_KEY + userId;
                redisTemplate.delete(cacheKey);
                
                log.info("更新用户{}画像成功", userId);
            }
            
            return result;
            
        } catch (JsonProcessingException e) {
            log.error("更新用户画像失败", e);
            return false;
        }
    }
    
    @Override
    public UserProfileDTO getUserProfile(Long userId) {
        // 检查缓存
        String cacheKey = USER_PROFILE_KEY + userId;
        Object cached = redisTemplate.opsForValue().get(cacheKey);
        if (cached != null) {
            return (UserProfileDTO) cached;
        }
        
        User user = userMapper.selectById(userId);
        if (user == null) {
            throw new RuntimeException("用户不存在");
        }
        
        UserProfileDTO profile = new UserProfileDTO();
        profile.setUserId(userId);
        profile.setConsumeFrequency(user.getConsumeFrequency());
        profile.setAvgOrderValue(BigDecimal.valueOf(user.getAvgOrderValue()));
        profile.setPriceSensitivity(user.getPriceSensitivity());
        
        try {
            // 解析JSON字段
            if (user.getPreferredCategories() != null) {
                List<String> categories = objectMapper.readValue(
                    user.getPreferredCategories(),
                    objectMapper.getTypeFactory().constructCollectionType(List.class, String.class)
                );
                profile.setPreferredCategories(categories);
            }
            
            if (user.getTags() != null) {
                List<String> tags = objectMapper.readValue(
                    user.getTags(),
                    objectMapper.getTypeFactory().constructCollectionType(List.class, String.class)
                );
                profile.setUserTags(tags);
            }
            
            if (user.getProfile() != null) {
                Map<String, Object> habits = objectMapper.readValue(
                    user.getProfile(),
                    objectMapper.getTypeFactory().constructMapType(Map.class, String.class, Object.class)
                );
                profile.setConsumptionHabits(habits);
            }
            
        } catch (JsonProcessingException e) {
            log.error("解析用户画像数据失败", e);
        }
        
        // 计算生命周期阶段
        profile.setLifecycleStage(calculateLifecycleStage(user));
        
        // 计算流失风险等级
        profile.setChurnRiskLevel(calculateChurnRiskLevel(user));
        
        // 缓存结果
        redisTemplate.opsForValue().set(cacheKey, profile, 1, TimeUnit.HOURS);
        
        return profile;
    }
    
    @Override
    public List<Long> collaborativeFilteringRecommend(Long userId, Integer limit) {
        // 获取用户历史行为数据
        LambdaQueryWrapper<UserCoupon> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserCoupon::getUserId, userId)
               .eq(UserCoupon::getStatus, "USED");
        
        List<UserCoupon> userCoupons = userCouponMapper.selectList(wrapper);
        
        if (userCoupons.isEmpty()) {
            // 新用户，返回热门券
            return getPopularCoupons(limit);
        }
        
        // 找到相似用户
        List<Long> similarUsers = findSimilarUsers(userId, userCoupons);
        
        // 基于相似用户推荐券
        return recommendBasedOnSimilarUsers(similarUsers, userId, limit);
    }
    
    @Override
    public List<Long> contentBasedRecommend(Long userId, Integer limit) {
        UserProfileDTO userProfile = getUserProfile(userId);
        
        // 基于用户画像推荐券
        LambdaQueryWrapper<Coupon> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Coupon::getStatus, "PUBLISHED")
               .gt(Coupon::getValidEndTime, LocalDateTime.now())
               .orderByDesc(Coupon::getAiWeight);
        
        List<Coupon> allCoupons = couponMapper.selectList(wrapper);
        
        // 根据用户画像计算匹配度
        Map<Long, Double> couponScores = new HashMap<>();
        
        for (Coupon coupon : allCoupons) {
            double score = calculateContentBasedScore(coupon, userProfile);
            couponScores.put(coupon.getId(), score);
        }
        
        // 按分数排序并返回前N个
        return couponScores.entrySet().stream()
                .sorted(Map.Entry.<Long, Double>comparingByValue().reversed())
                .limit(limit)
                .map(Map.Entry::getKey)
                .collect(Collectors.toList());
    }
    
    @Override
    public List<Long> hybridRecommend(Long userId, Integer limit) {
        // 协同过滤推荐
        List<Long> cfRecommendations = collaborativeFilteringRecommend(userId, limit * 2);
        
        // 基于内容推荐
        List<Long> cbRecommendations = contentBasedRecommend(userId, limit * 2);
        
        // 混合推荐结果
        Map<Long, Double> hybridScores = new HashMap<>();
        
        // 协同过滤权重0.6，内容推荐权重0.4
        for (int i = 0; i < cfRecommendations.size(); i++) {
            Long couponId = cfRecommendations.get(i);
            double score = 0.6 * (1.0 - (double) i / cfRecommendations.size());
            hybridScores.put(couponId, hybridScores.getOrDefault(couponId, 0.0) + score);
        }
        
        for (int i = 0; i < cbRecommendations.size(); i++) {
            Long couponId = cbRecommendations.get(i);
            double score = 0.4 * (1.0 - (double) i / cbRecommendations.size());
            hybridScores.put(couponId, hybridScores.getOrDefault(couponId, 0.0) + score);
        }
        
        return hybridScores.entrySet().stream()
                .sorted(Map.Entry.<Long, Double>comparingByValue().reversed())
                .limit(limit)
                .map(Map.Entry::getKey)
                .collect(Collectors.toList());
    }
    
    @Override
    public Double predictCouponUsageProbability(Long userId, Long couponId) {
        UserProfileDTO userProfile = getUserProfile(userId);
        Coupon coupon = couponMapper.selectById(couponId);
        
        if (coupon == null) {
            return 0.0;
        }
        
        // 基于用户画像和券特征预测使用概率
        double probability = 0.5; // 基础概率
        
        // 根据价格敏感度调整
        if ("HIGH".equals(userProfile.getPriceSensitivity())) {
            probability += 0.2;
        } else if ("LOW".equals(userProfile.getPriceSensitivity())) {
            probability -= 0.1;
        }
        
        // 根据消费频次调整
        if (userProfile.getConsumeFrequency() != null && userProfile.getConsumeFrequency() > 5) {
            probability += 0.1;
        }
        
        // 根据券类型调整
        if ("DIRECT_REDUCTION".equals(coupon.getType())) {
            probability += 0.1;
        }
        
        return Math.min(1.0, Math.max(0.0, probability));
    }
    
    @Override
    public boolean adjustCouponStock(Long couponId, String reason) {
        Coupon coupon = couponMapper.selectById(couponId);
        if (coupon == null) {
            return false;
        }
        
        // 根据原因调整库存
        switch (reason) {
            case "LOW_USAGE":
                // 使用率低，减少库存
                coupon.setTotalStock(Math.max(1, coupon.getTotalStock() / 2));
                break;
            case "HIGH_DEMAND":
                // 需求高，增加库存
                coupon.setTotalStock(coupon.getTotalStock() * 2);
                break;
            case "EXPIRING_SOON":
                // 即将过期，降低门槛
                coupon.setThreshold(coupon.getThreshold().multiply(BigDecimal.valueOf(0.8)));
                break;
        }
        
        boolean result = couponMapper.updateById(coupon) > 0;
        
        if (result) {
            log.info("智能调整券{}库存，原因：{}", couponId, reason);
        }
        
        return result;
    }
    
    @Override
    public AIRecommendationDTO generatePushStrategy(Long userId) {
        UserProfileDTO userProfile = getUserProfile(userId);
        
        AIRecommendationDTO strategy = new AIRecommendationDTO();
        strategy.setCouponIds(generatePersonalizedCoupons(userId, 5));
        strategy.setReason("基于您的消费习惯推荐");
        strategy.setScore(0.85);
        strategy.setStrategy("PERSONALIZED");
        
        List<String> tags = new ArrayList<>();
        if ("HIGH".equals(userProfile.getPriceSensitivity())) {
            tags.add("价格敏感");
        }
        if (userProfile.getConsumeFrequency() != null && userProfile.getConsumeFrequency() > 3) {
            tags.add("高频用户");
        }
        strategy.setTags(tags);
        
        // 计算预期核销率
        double expectedRate = strategy.getCouponIds().stream()
                .mapToDouble(couponId -> predictCouponUsageProbability(userId, couponId))
                .average()
                .orElse(0.0);
        strategy.setExpectedUsageRate(expectedRate);
        
        return strategy;
    }
    
    /**
     * 根据用户画像调整券面值
     */
    private void adjustCouponValueByProfile(Coupon dynamicCoupon, UserProfileDTO userProfile, Coupon baseCoupon) {
        BigDecimal multiplier = BigDecimal.ONE;
        
        if ("HIGH".equals(userProfile.getPriceSensitivity())) {
            multiplier = BigDecimal.valueOf(1.2); // 价格敏感用户，增加面值
        } else if ("LOW".equals(userProfile.getPriceSensitivity())) {
            multiplier = BigDecimal.valueOf(0.8); // 价格不敏感用户，减少面值
        }
        
        dynamicCoupon.setValue(baseCoupon.getValue().multiply(multiplier));
    }
    
    /**
     * 根据用户画像调整券有效期
     */
    private void adjustCouponValidityByProfile(Coupon dynamicCoupon, UserProfileDTO userProfile) {
        LocalDateTime now = LocalDateTime.now();
        
        if (userProfile.getConsumeFrequency() != null && userProfile.getConsumeFrequency() > 5) {
            // 高频用户，延长有效期
            dynamicCoupon.setValidStartTime(now);
            dynamicCoupon.setValidEndTime(now.plusDays(15));
        } else {
            // 低频用户，缩短有效期
            dynamicCoupon.setValidStartTime(now);
            dynamicCoupon.setValidEndTime(now.plusDays(7));
        }
    }
    
    /**
     * 根据用户画像调整券使用门槛
     */
    private void adjustCouponThresholdByProfile(Coupon dynamicCoupon, UserProfileDTO userProfile) {
        if (userProfile.getAvgOrderValue() != null) {
            // 根据平均客单价设置门槛
            BigDecimal threshold = userProfile.getAvgOrderValue().multiply(BigDecimal.valueOf(0.8));
            dynamicCoupon.setThreshold(threshold);
        }
    }
    
    /**
     * 计算用户生命周期阶段
     */
    private String calculateLifecycleStage(User user) {
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime lastConsumeTime = user.getLastConsumeTime();
        
        if (lastConsumeTime == null) {
            return "NEW_USER";
        }
        
        long daysSinceLastConsume = java.time.Duration.between(lastConsumeTime, now).toDays();
        
        if (daysSinceLastConsume <= 7) {
            return "ACTIVE";
        } else if (daysSinceLastConsume <= 30) {
            return "AT_RISK";
        } else {
            return "DORMANT";
        }
    }
    
    /**
     * 计算用户流失风险等级
     */
    private String calculateChurnRiskLevel(User user) {
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime lastConsumeTime = user.getLastConsumeTime();
        
        if (lastConsumeTime == null) {
            return "HIGH";
        }
        
        long daysSinceLastConsume = java.time.Duration.between(lastConsumeTime, now).toDays();
        
        if (daysSinceLastConsume <= 7) {
            return "LOW";
        } else if (daysSinceLastConsume <= 15) {
            return "MEDIUM";
        } else {
            return "HIGH";
        }
    }
    
    /**
     * 获取热门券
     */
    private List<Long> getPopularCoupons(Integer limit) {
        LambdaQueryWrapper<Coupon> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Coupon::getStatus, "PUBLISHED")
               .gt(Coupon::getValidEndTime, LocalDateTime.now())
               .orderByDesc(Coupon::getReceivedCount)
               .last("LIMIT " + limit);
        
        List<Coupon> coupons = couponMapper.selectList(wrapper);
        return coupons.stream().map(Coupon::getId).collect(Collectors.toList());
    }
    
    /**
     * 找到相似用户
     */
    private List<Long> findSimilarUsers(Long userId, List<UserCoupon> userCoupons) {
        // TODO: 实现相似用户查找算法
        // 基于用户券使用历史计算用户相似度
        return Arrays.asList(1L, 2L, 3L); // 临时返回
    }
    
    /**
     * 基于相似用户推荐券
     */
    private List<Long> recommendBasedOnSimilarUsers(List<Long> similarUsers, Long userId, Integer limit) {
        // TODO: 实现基于相似用户的推荐算法
        return getPopularCoupons(limit); // 临时返回热门券
    }
    
    /**
     * 计算基于内容的推荐分数
     */
    private double calculateContentBasedScore(Coupon coupon, UserProfileDTO userProfile) {
        double score = 0.0;
        
        // 根据价格敏感度匹配
        if ("HIGH".equals(userProfile.getPriceSensitivity()) && 
            "DIRECT_REDUCTION".equals(coupon.getType())) {
            score += 0.3;
        }
        
        // 根据消费频次匹配
        if (userProfile.getConsumeFrequency() != null && 
            userProfile.getConsumeFrequency() > 5 && 
            "LADDER".equals(coupon.getType())) {
            score += 0.2;
        }
        
        // 根据AI权重
        if (coupon.getAiWeight() != null) {
            score += coupon.getAiWeight().doubleValue() * 0.1;
        }
        
        return score;
    }
}
